package com.blue.jdbc;

import java.lang.reflect.ParameterizedType;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.springframework.jdbc.core.JdbcTemplate;

import com.blue.jdbc.annotation.LockModeType;

public class BaseDao<T> implements IPageable<T>
{
	protected JdbcTemplate jdbcTemplate;
	protected JdbcObjectTemplate jdbcObjectTemplate;

	protected Class<T> clazz;

	@SuppressWarnings("unchecked")
	public BaseDao()
	{
		this.clazz = (Class<T>)((ParameterizedType)getClass().getGenericSuperclass())
				.getActualTypeArguments()[0];
	}

	/**
	 * 保存对象，动态生成SQL
	 * 
	 * @param object 对象
	 * @return 影响记录数
	 */
	public int save(T object)
	{
		return jdbcObjectTemplate.save(object);
	}
	
	/**
	 * 保存对象
	 * 
	 * @param object 对象
	 * @param dynamic 是否动态生成SQL
	 * @return 影响记录数
	 */
	public int save(T object, boolean dynamic)
	{
		return jdbcObjectTemplate.save(object, dynamic);
	}
	
	/**
	 * 保存对象
	 * 
	 * @param params [字段名0, 字段值0, 字段名1, 字段值1...]
	 * @return 影响记录数
	 */
	public int saveObject(Object...params)
	{
		return jdbcObjectTemplate.saveObject(clazz, params);
	}
	
	/**
	 * 保存对象列表，不动态生成SQL
	 * 
	 * @param objectList 对象列表
	 * @return 影响记录数
	 */
	public int[] saveList(List<T> objectList)
	{
		return jdbcObjectTemplate.saveList(objectList);
	}
	
	/**
	 * 删除对象
	 * 
	 * @param object 对象
	 * @return 影响记录数
	 */
	public int delete(T object)
	{
		return jdbcObjectTemplate.delete(object);
	}
	
	/**
	 * 根据主键删除对象
	 * 
	 * @param id 主键
	 * @return 影响数据库记录数
	 */
	public int deleteId(Object id)
	{
		return jdbcObjectTemplate.deleteId(clazz, id);
	}
	
	/**
	 * 根据ID列表删除对象
	 * 
	 * @param idList ID列表
	 * @return 影响记录数
	 */
	public <K> int delete(List<K> idList)
	{
		return jdbcObjectTemplate.delete(clazz, idList);
	}
	
	/**
	 * 根据字段值删除
	 * 
	 * @param params [字段名0, 字段值0, 字段名1, 字段值1...]
	 * @return 影响记录数
	 */
	public int deleteBy(Object...params)
	{
		return jdbcObjectTemplate.deleteBy(clazz, params);
	}
	
	/**
	 * 更新对象，动态生成SQL
	 * 
	 * @param object 对象
	 * @return 影响记录数
	 */
	public int update(T object)
	{
		return jdbcObjectTemplate.update(object);
	}
	
	/**
	 * 更新对象
	 * 
	 * @param object 对象
	 * @param dynamic 是否动态生成SQL
	 * @return 影响记录数
	 */
	public int update(T object, boolean dynamic)
	{
		return jdbcObjectTemplate.update(object, dynamic);
	}
	
	/**
	 * 更新对象
	 * 
	 * @param id 对象主键
	 * @param params [字段名0, 字段值0, 字段名1, 字段值1...]
	 * @return 影响记录数
	 */
	public int updateObject(Object id, Object...params)
	{
		return jdbcObjectTemplate.updateObject(clazz, id, params);
	}
	
	/**
	 * 更新对象列表，不动态生成SQL
	 * 
	 * @param objectList 对象列表
	 * @return 影响记录数
	 */
	public int[] updateList(List<T> objectList)
	{
		return jdbcObjectTemplate.updateList(objectList);
	}
	
	/**
	 *  对象属性自增长
	 * 
	 * @param id 对象主键
	 * @param  params [字段名0(字符串), 增长值0(数字), 字段名1(字符串), 增长值1(数字)...]
	 * @return 影响记录数
	 */
	public int inc(Object id, Object...params)
	{
		return jdbcObjectTemplate.inc(clazz, id, params);
	}
	
	/**
	 * 根据主键取得对象
	 * 
	 * @param id 主键
	 * @return 对象
	 */
	public T get(Object id)
	{
		T t = jdbcObjectTemplate.get(clazz, id);
		return t;
	}
	
	/**
	 * 根据主键取得对象
	 * 
	 * @param id 主键
	 * @param type 锁类型
	 * @return 对象
	 */
	public T get(Object id, LockModeType type)
	{
		T t = jdbcObjectTemplate.get(clazz, id, type);
		return t;
	}
	
	/**
	 * 根据主键取得对象
	 * 
	 * @param id 主键
	 * @return 对象
	 */
	public T getSelect(Object id)
	{
		String column = jdbcObjectTemplate.getIdColumn(clazz, true);
		Map<String, Object> param = new HashMap<>();
		param.put("id", id);
		StringBuilder sql = this.select();
		sql.append(" and a.").append(column).append("=:id");
		return jdbcObjectTemplate.get(clazz, sql.toString(), param);
	}
	
	/**
	 * 查询一个字段
	 * 
	 * @param target 字段类型
	 * @param field 字段名称
	 * @param params [字段名0, 字段值0, 字段名1, 字段值1...]
	 * @return 字段值
	 */
	public <K> K getField(Class<K> target, String field, Object...params)
	{
		return jdbcObjectTemplate.getField(clazz, target, field, params);
	}
	
	/**
	 * 查询一个对象
	 * 
	 * @param params [字段名0, 字段值0, 字段名1, 字段值1...]
	 * @return 对象
	 */
	public T getObject(Object...params)
	{
		return jdbcObjectTemplate.getObject(clazz, params);
	}
	
	/**
	 * 根据主键列表取得对象Map
	 * 
	 * @param idList 主键列表
	 * @return 对象Map
	 */
	public <K> Map<K, T> getList(Collection<K> idList)
	{
		Map<K, T> map = jdbcObjectTemplate.get(clazz, idList);
		return map;
	}
	
	/**
	 * 判断对象某些字段是否存在
	 * 
	 * @param object 对象
	 * @param names 字段列表
	 * @return true表示存在，false表示不存在
	 */
	public boolean exist(T object, String...names)
	{
		boolean exist = jdbcObjectTemplate.exist(object, names);
		return exist;
	}
	
	/**
	 * 查询记录数
	 * 
	 * @param params [字段名0, 字段值0, 字段名1, 字段值1...]
	 * @return 记录数
	 */
	public int count(Object...params)
	{
		return jdbcObjectTemplate.count(clazz, params);
	}
	
	/* (non-Javadoc)
	 * @see com.blue.jdbc.IPageable#getRows(java.util.Map)
	 */
	public int getRows(T param)
	{
		String table = jdbcObjectTemplate.getTable(clazz, true);
		StringBuilder sql = new StringBuilder(String.format("select count(*) from %s a where 1=1", table));

		this.query(sql, param);
		
		return jdbcObjectTemplate.queryForInt(sql.toString(), param);
	}
	
	/**
	 * 列出在数据库中的所有对象，不分页
	 * 
	 * @param param 查询参数
	 * @return 对象列表
	 */
	public List<T> list(T param)
	{
		StringBuilder sql = this.select();
		this.query(sql, param);
		List<T> list = jdbcObjectTemplate.list(clazz, sql.toString(), param);
		return list;
	}
	
	/* (non-Javadoc)
	 * @see com.blue.jdbc.IPageable#list(java.util.Map, int, int)
	 */
	public List<T> list(T param, int start, int size)
	{
		StringBuilder sql = this.select();
		this.query(sql, param);
		List<T> list = jdbcObjectTemplate.list(clazz, sql.toString(), param, start, size);
		return list;
	}
	
	/* (non-Javadoc)
	 * @see com.blue.jdbc.IPageable#list(java.util.Map, com.blue.jdbc.Page)
	 */
	public Page<T> list(T param, Page<T> page)
	{
		if (page == null)
			page = new Page<T>();
		
		StringBuilder where = new StringBuilder();
		this.query(where, param);
		
		int rows = this.getRows(param);
		page.setRows(rows);
		
		StringBuilder select = this.select();
		select.append(where);
		List<T> list = jdbcObjectTemplate.list(clazz, select.toString(), param, page.getStartRowNo(), page.getSize());
		page.setObjectList(list);
		
		return page;
	}
	
	/**
	 * 查询字段列表
	 * 
	 * @param target 字段类型
	 * @param field 字段名称
	 * @param params [字段名0, 字段值0, 字段名1, 字段值1...]
	 * @return 字段列表
	 */
	public <K> List<K> listField(Class<K> target, String field, Object...params)
	{
		return jdbcObjectTemplate.listField(clazz, target, field, params);
	}
	
	/**
	 * 查询对象列表
	 * 
	 * @param clazz 对象类型
	 * @param params [字段名0, 字段值0, 字段名1, 字段值1...]
	 * @return 对象列表
	 */
	public List<T> listObject(Object...params)
	{
		return jdbcObjectTemplate.listObject(clazz, params);
	}
	
	/**
	 * <p>创建 select 查询语句，<b>子类通过覆盖该方法来自定投影</b></p>
	 * 
	 * @return select 查询语句
	 */
	protected StringBuilder select()
	{
		StringBuilder sql = new StringBuilder(String.format(
				"SELECT a.* FROM %s a WHERE 1=1 ", jdbcObjectTemplate.getTable(clazz, true)));
		return sql;
	}
	
	/**
	 * <p>创建查询 WHERE 子句，<b>子类通过覆盖该方法来自定义查询</b></p>
	 * <b>注：父类该方法并没作任何查询
	 * 
	 * @param sql 拼接SQL语句
	 * @param param 查询参数
	 */
	protected void query(StringBuilder sql, T param)
	{
	}

	public void setJdbcTemplate(JdbcTemplate jdbcTemplate)
	{
		this.jdbcTemplate = jdbcTemplate;
	}

	public void setJdbcObjectTemplate(JdbcObjectTemplate jdbcObjectTemplate)
	{
		this.jdbcObjectTemplate = jdbcObjectTemplate;
	}

}
